﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;
using System.Collections;
using System.IO;


namespace Typo3ImageUpload
{
    public partial class Form2 : Form
    {
        // Start Pfad
        private string startPath;
        // aktuell ausgewähler Pfad
        private string actPath;
        // ausgewähltes Bild
        private string actImage;
        // Thread PopulateLargeImageList
        private Thread populateLargeImageListThread;
        // Wird auf True gesetzt wenn Auswahl von Listview gelöscht wird.
        bool clearSelected;

        public Form2()
        {
            InitializeComponent();
            this.listViewPictures.View = View.LargeIcon;
            this.listViewPictures.LargeImageList = new ImageList();
            this.listViewPictures.LargeImageList.ImageSize = new Size(160, 160);

            //Startverzeichnis
            this.startPath = "c:\\";
            this.actPath = "c:\\";
            if(Directory.Exists(Properties.Settings.Default.startdir)){
                this.startPath = Properties.Settings.Default.startdir;
                this.actPath = Properties.Settings.Default.startdir;
            }

            //Tree laden
            this.treeFSView.Load((string)this.actPath);

            enableExifEditFields(false);

            //InitializePictureBox();
            PopulateListView();

            // Thread vorbereiten
            CheckForIllegalCrossThreadCalls = false;
        }

        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Thread beenden wenn er gerade am laufen ist
            if (this.populateLargeImageListThread is Thread && this.populateLargeImageListThread.IsAlive)
            {
                this.populateLargeImageListThread.Abort();
            }
        }

        private void changeListViewModus(View view)
        {
            this.listViewPictures.View = view;
            this.listViewPictures.Refresh();
        }
        
        private void treeFSView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.actPath = getActPath();
            enableExifEditFields(false);
            this.PopulateListView();
        }

        // Gibt den aktuellen Pfad aus den Nodes zurück
        private string getActPath()
        {
            string actPath = "";
            TreeNode actNode = this.treeFSView.SelectedNode;

            while (actNode is TreeNode && actNode.Parent != null) {
                actPath = actNode.Text + "\\" + actPath;
                actNode = actNode.Parent;
            }
            return this.startPath + actPath;
        }



        /// <summary>
        /// Ändert die Größe eines Bildes und setzt eine Hintergrundfarbe.
        /// </summary>
        /// <param name="Source">Originalbild als Image</param>
        /// <param name="Width">Neue Breite in Pixel</param>
        /// <param name="Height">Neue Höhe in Pixel</param>
        /// <param name="Absolut">Wenn true wird ein Image mit exakt den angegebenen Maßen erstellt. Das Bild wird mittig plaziert und mit der angegebenen Farbe gefüllt. Seitenverhältnisse des Bildes selbst bleiben erhalten. Wenn False dann wird entsprechend dem kleinem Faktor das neue Bild berechnet (neues Bild hat dann aber ggfs. NICHT die angegebenen Maße!)</param>
        /// <param name="Fill">Füllfarbe für Hintergrund (vorallem wichtig bei Absolut = true oder Transparenten Bildern (PNG)</param>
        /// <param name="MaxFactorX">Maximaler Vergrößerungsfaktor X-Achse. Wenn aus Width = 10 z.B. 1000 werden soll, so kann der Wert 2 ein maximales verdoppeln ermöglichen. Das Bild hat dann Width = 20. -1 bedeutet kein Mindestfaktor</param>
        /// <param name="MaxFactorY">Maximaler Vergrößerungsfaktor Y-Achse. Wenn aus Height = 10 z.B. 1000 werden soll, so kann der Wert 2 ein maximales verdoppeln ermöglichen. Das Bild hat dann Height = 20. -1 bedeutet kein Mindestfaktor</param>
        /// <returns>Bitmap / Image</returns>
        public static Image ResizePic(Image Source, int Width, int Height, bool Absolut, Color Fill, double MaxFactorX, double MaxFactorY)
        {
            if (Source != null)
            {
                // Faktoren für X und Y Achse berechnen
                double dblFaktorX = (double)Width / (double)Source.Width;
                if (dblFaktorX > MaxFactorX & MaxFactorX > -1)
                {
                    Width = (int)((double)Source.Width * MaxFactorX);
                    dblFaktorX = MaxFactorX;
                }

                double dblFaxtorY = (double)Height / (double)Source.Height;
                if (dblFaxtorY > MaxFactorY & MaxFactorY > -1)
                {
                    Height = (int)((double)Source.Height * MaxFactorY);
                    dblFaxtorY = MaxFactorY;
                }

                // kleinern Faktor benutzen
                double dblFaktorUse;
                if (dblFaktorX < dblFaxtorY)
                    dblFaktorUse = dblFaktorX;
                else
                    dblFaktorUse = dblFaxtorY;

                int intNewX = (int)((double)Source.Width * dblFaktorUse);
                int intNewY = (int)((double)Source.Height * dblFaktorUse);

                Bitmap objNewImage;
                int intPosX, intPosY;

                if (Absolut)
                {
                    objNewImage = new Bitmap(Width, Height);
                    intPosX = (Width - intNewX) / 2;
                    intPosY = (Height - intNewY) / 2;
                }
                else
                {
                    objNewImage = new Bitmap(intNewX, intNewY);
                    intPosX = 0;
                    intPosY = 0;
                }

                using (Graphics objGfx = Graphics.FromImage(objNewImage))
                {
                    objGfx.FillRectangle(new SolidBrush(Fill), 0, 0, objNewImage.Width, objNewImage.Height);
                    objGfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    objGfx.DrawImage(Source, new Rectangle(intPosX, intPosY, intNewX, intNewY));
                }
                return objNewImage;
            }
            else
                return null;
        }


        private void PopulateListView()
        {
            // Thread beenden wenn er gerade am laufen ist
            if (this.populateLargeImageListThread is Thread && this.populateLargeImageListThread.IsAlive)
            {
                this.populateLargeImageListThread.Abort();
            }
            listViewPictures.Clear();
            listViewPictures.LargeImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth24Bit;

            // Declare and construct the ColumnHeader objects.
            ColumnHeader header1, header2, header3, header4 ,header5;
            header1 = new ColumnHeader();
            header2 = new ColumnHeader();
            header3 = new ColumnHeader();
            header4 = new ColumnHeader();
            header5 = new ColumnHeader();

            // Set the text, alignment and width for each column header.
            header1.Text = "Dateiname";
            header1.TextAlign = HorizontalAlignment.Left;
            header1.Width = 150;

            header2.TextAlign = HorizontalAlignment.Left;
            header2.Text = "Pfad";
            header2.Width = 200;

            header3.TextAlign = HorizontalAlignment.Left;
            header3.Text = "Titel";
            header3.Width = 100;

            header4.TextAlign = HorizontalAlignment.Left;
            header4.Text = "Author";
            header4.Width = 100;

            header5.TextAlign = HorizontalAlignment.Left;
            header5.Text = "Kommentar";
            header5.Width = 400;

            // Add the headers to the ListView control.
            listViewPictures.Columns.Add(header1);
            listViewPictures.Columns.Add(header2);
            listViewPictures.Columns.Add(header3);
            listViewPictures.Columns.Add(header4);
            listViewPictures.Columns.Add(header5);

            // Populate the ListView.Items property.
            // Set the directory to the sample picture directory.
            System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(this.actPath);

            // Get the .jpg files from the directory
            System.IO.FileInfo[] files = dirInfo.GetFiles("*.jpg");

            // Add each file name and full name including path
            // to the ListView.
            btnUpload.Enabled = false;
            if (files.Length > 0)
            {
                btnUpload.Enabled = true;

                this.Cursor = Cursors.WaitCursor;
                foreach (System.IO.FileInfo file in files)
                {
                    ListViewItem item = new ListViewItem(file.Name);
                    item.SubItems.Add(file.FullName);
                    item.ImageKey = file.Name;
                    item.SubItems.Add("");
                    item.SubItems.Add("");
                    item.SubItems.Add("");
                    listViewPictures.Items.Add(item);
                    listViewPictures.Refresh();
                }
                // Thread starten um Listview mit Bilder zu füllen
                this.populateLargeImageListThread = new Thread(new ThreadStart(populateLargeImageList));
                this.populateLargeImageListThread.Start();
                this.Cursor = Cursors.Default;
                Console.Write("Thread PopulateListView fertig!");
            }
        }

        // Thread zum füllen des ImageList
        private void populateLargeImageList()
        {
            this.progressBar1.Minimum = 1;
            this.progressBar1.Maximum = this.listViewPictures.Items.Count;
            this.progressBar1.Value = 1;
            this.progressBar1.Step = 1;

            this.listViewPictures.LargeImageList.Images.Clear();
            for (int i=0; i<this.listViewPictures.Items.Count; i++)
            {
                System.Drawing.Image myImage = Image.FromFile(this.listViewPictures.Items[i].SubItems[1].Text);
                PropertyItem[] pitems = myImage.PropertyItems;
                myImage = ResizePic(myImage, 160, 160, true, Color.Transparent, -1, -1);
                this.listViewPictures.LargeImageList.Images.Add(this.listViewPictures.Items[i].Text, myImage);

                // Exif Daten in Liste einfügen
                foreach (PropertyItem pi in pitems)
                {
                    // Titel
                    if (pi.Id == 40091) listViewPictures.Items[i].SubItems[2].Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                    // Kommentar
                    if (pi.Id == 40092) listViewPictures.Items[i].SubItems[4].Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                    // Author
                    if (pi.Id == 40093) listViewPictures.Items[i].SubItems[3].Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                }
                
                myImage.Dispose();
                GC.Collect();
                this.listViewPictures.Refresh();
                this.progressBar1.PerformStep();
            }
            // Progressbar zurücksetzen
            this.progressBar1.Value = this.progressBar1.Maximum;
            Thread.Sleep(1000);
            this.progressBar1.Value = 1;
        }

        private void listViewPictures_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ListViewItem selection = listViewPictures.GetItemAt(e.X, e.Y);
            if (selection != null)
            {
                Preview preview = new Preview();
                preview.Show();
                ((Preview)Application.OpenForms["Preview"]).picboxPreviewPicture.Image = System.Drawing.Image.FromFile(selection.SubItems[1].Text);
            }
        }


        // Exif Datenfelder aktivieren oder deaktivieren
        private void enableExifEditFields(bool enable)
        {
            this.txtComment.Text = "";
            this.cboAuthor.Text = "";
            this.cboTitle.Text = "";

            this.cboTitle.Enabled = enable;
            this.txtComment.Enabled = enable;
            this.cboAuthor.Enabled = enable;
            this.lblTitel.Enabled = enable;
            this.lblComment.Enabled = enable;
            this.lblAuthor.Enabled = enable;

            if (picboxActPicture.Image is Image)
            {
                picboxActPicture.Image.Dispose();
                picboxActPicture.Image = null;
            }
            picboxActPicture.SizeMode = PictureBoxSizeMode.Zoom;

            btn_save.Enabled = enable;
            btn_cancel.Enabled = enable;
        }

        private void save(object sender, EventArgs e)
        {
            // Thread beenden wenn er gerade am laufen ist
            if (this.populateLargeImageListThread is Thread && this.populateLargeImageListThread.IsAlive)
            {
                this.populateLargeImageListThread.Abort();
            }
            this.Cursor = Cursors.WaitCursor;

            this.progressBar1.Minimum = 1;
            this.progressBar1.Maximum = this.listViewPictures.SelectedItems.Count;
            this.progressBar1.Value = 1;
            this.progressBar1.Step = 1;

            // Datei aus Picturebox freigeben
            picboxActPicture.Image.Dispose();
            ListView.SelectedListViewItemCollection pics = this.listViewPictures.SelectedItems;
            foreach (ListViewItem pic in pics)
                {
                string imageFileName = pic.SubItems[1].Text;
                System.Drawing.Image image = Image.FromFile(imageFileName); 
                PropertyItem[] propItem = image.PropertyItems;

                // Titel setzen
                byte[] bTitle = System.Text.UnicodeEncoding.Unicode.GetBytes(this.cboTitle.Text);
                if (bTitle.Length > 0 && this.cboTitle.Text != "<beibehalten>")
                {
                    propItem[0].Type = 1;
                    propItem[0].Id = 40091;
                    propItem[0].Len = bTitle.Length;
                    propItem[0].Value = bTitle;
                    image.SetPropertyItem(propItem[0]);
                }

                // Kommentar setzen
                byte[] bComment = System.Text.UnicodeEncoding.Unicode.GetBytes(this.txtComment.Text);
                if (bComment.Length > 0 && this.txtComment.Text != "<beibehalten>")
                {
                    propItem[0].Type = 1;
                    propItem[0].Id = 40092;
                    propItem[0].Len = bComment.Length;
                    propItem[0].Value = bComment;
                    image.SetPropertyItem(propItem[0]);
                }

                // Author setzen
                byte[] bAuthor = System.Text.UnicodeEncoding.Unicode.GetBytes(this.cboAuthor.Text);
                if (bAuthor.Length > 0 && this.cboAuthor.Text != "<beibehalten>")
                {
                    propItem[0].Type = 1;
                    propItem[0].Id = 40093;
                    propItem[0].Len = bAuthor.Length;
                    propItem[0].Value = bAuthor;
                    image.SetPropertyItem(propItem[0]);
                }

                image.Save(imageFileName + ".tmp");
                // Image Resourcen frei geben und umbenennen.
                image.Dispose();
                GC.Collect();
                System.IO.File.Delete(imageFileName);
                System.IO.File.Move(imageFileName + ".tmp", imageFileName);
                this.progressBar1.PerformStep();
            }
            enableExifEditFields(false);
            this.clearSelected = true;
            this.listViewPictures.SelectedItems.Clear();
            this.clearSelected = false;
            this.Cursor = Cursors.Default;

            // Thread starten um Listview zu aktualisieren
            this.populateLargeImageListThread = new Thread(new ThreadStart(populateLargeImageList));
            this.populateLargeImageListThread.Start();

            // Progressbar zurücksetzen
            this.progressBar1.Value = this.progressBar1.Maximum;
            Thread.Sleep(1000);
            this.progressBar1.Value = 1;

        }

        private void btn_startgetpath_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.SelectedPath = this.startPath;
            folderBrowserDialog1.Description = "Wählen Sie das Verzeichnis aus wo sich Ihre Fotos befinden.";
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                this.actPath = folderBrowserDialog1.SelectedPath;
                // Wenn nicht ein RootPfad dann Backslash noch dazugeben.
                if (this.actPath != System.IO.Path.GetPathRoot(this.actPath))
                {
                    this.actPath = this.actPath + "\\";
                }
                this.startPath = this.actPath;
                Properties.Settings.Default.startdir = this.startPath;
                this.treeFSView.Load((string)this.actPath);

            }
        }

        private void btn_cancel_Click(object sender, EventArgs e)
        {
            enableExifEditFields(false);
            this.clearSelected = true;
            this.listViewPictures.SelectedItems.Clear();
            this.clearSelected = false;
        }

        private void listViewPictures_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Es wird gerade die Auswahl gelöscht, daher muss der Inhalt nicht jedesmal neu gezeichnet werden
            if (this.clearSelected) { return; }
            
            ListView.SelectedListViewItemCollection pics = this.listViewPictures.SelectedItems;

            this.Cursor = Cursors.WaitCursor;
            this.lbl_multichoice.Visible = false;

            // ComboBox leeren
            this.cboTitle.Items.Clear();
            this.cboAuthor.Items.Clear();

            if (pics.Count == 1)
            {
                enableExifEditFields(true);

                this.actImage = pics[0].SubItems[1].Text;
                picboxActPicture.Image = System.Drawing.Image.FromFile(this.actImage);

                PropertyItem[] items = picboxActPicture.Image.PropertyItems;
                foreach (PropertyItem pi in items)
                {
                    // Titel
                    if (pi.Id == 40091) this.cboTitle.Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                    // Kommentar
                    if (pi.Id == 40092) this.txtComment.Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                    // Author
                    if (pi.Id == 40093) this.cboAuthor.Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                    // Schlüsselworte ToDo
                    //if (pi.Id == 40093) this.???.Text = System.Text.ASCIIEncoding.Unicode.GetString(pi.Value);
                }
            }
            else if (pics.Count > 1)
            {
                this.lbl_multichoice.Visible = true;

                // Subitems: 2=Titel,3=Author,4=Kommentar
                // Titel Combobox vorbereiten
                string actTitle = pics[0].SubItems[2].Text;
                this.cboTitle.Items.Add("<beibehalten>");
                this.cboTitle.Items.Add("<entfernen>");
                this.cboTitle.Items.Add(pics[0].SubItems[2].Text);
                this.cboTitle.Text = actTitle;
                // Author Combox vorbereiten
                string actAuthor = pics[0].SubItems[3].Text;
                this.cboAuthor.Items.Add("<beibehalten>");
                this.cboAuthor.Items.Add("<entfernen>");
                this.cboAuthor.Items.Add(pics[0].SubItems[3].Text);
                this.cboAuthor.Text = actAuthor;

                string actComment = pics[0].SubItems[4].Text;
                foreach (ListViewItem pic in pics)
                {
                    if (pic.SubItems[2].Text != actTitle)
                    {
                        this.cboTitle.Text = "<beibehalten>";
                        this.cboTitle.Items.Add(pic.SubItems[2].Text);
                    }
                    if (pic.SubItems[3].Text != actAuthor)
                    {
                        this.cboAuthor.Text = "<beibehalten>";
                        this.cboAuthor.Items.Add(pic.SubItems[3].Text);
                    }
                    if (pic.SubItems[4].Text != actComment)
                    {
                        this.txtComment.Text = "<beibehalten>";
                    }
                    Console.Write(pic.SubItems[1].Text + "\n");
                }
            }
            this.Cursor = Cursors.Default;
        }

        private void btn_largeicon_Click(object sender, EventArgs e)
        {
            changeListViewModus(View.LargeIcon);
        }

        private void btn_tile_Click(object sender, EventArgs e)
        {
            changeListViewModus(View.Tile);
        }

        private void btn_detail_Click(object sender, EventArgs e)
        {
            changeListViewModus(View.Details);
        }

        private void btnUpload_Click(object sender, EventArgs e)
        {
            //ArrayList erzeugen
            ArrayList images = new ArrayList();
            ListView.SelectedListViewItemCollection pics = this.listViewPictures.SelectedItems;
            if (pics.Count >= 1)
            {
                foreach (ListViewItem pic in pics)
                {
                    images.Add(pic.SubItems[1].Text);
                }
                //Wizard starten
                UploadWizard upw = new UploadWizard(images);
                upw.ShowDialog();
            }
        }
    }
}
